/**
 * MIT License
 * 
 * Copyright (c) 2017 CaiDongyu
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.tunnel.server.tcp;
  
import com.tunnel.common.tcp.TcpBaseHandler;
import com.tunnel.common.tunnel.TunnelDataQueueManager;
import com.tunnel.common.util.HttpUtil;
import com.tunnel.common.util.StringUtil;
import com.tunnel.server.tcp.TcpClientManager.TcpClient;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;  
  
public class TcpServerHandler extends TcpBaseHandler{  
    public static final AttributeKey<String> TCP_CONNECTIONID_KEY = AttributeKey.valueOf("tcp.connectionid"); 
    public int port;
    public int portIndex;
    
    public TcpServerHandler(int port,int portIndex) {
    	super("Tcp-Server");
    	this.port = port;
    	this.portIndex = portIndex;
	}
    
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
    	super.channelActive(ctx);
    	
    	Attribute<String> attr = ctx.attr(TCP_CONNECTIONID_KEY);
		TcpClient tunnelClient = TcpClientManager.get(port);
		if(tunnelClient != null){//同一个http连接下，对requestId只设置一次
			//前16个字符是
			//connectionId 时间戳+三位随机数，代表http请求的编号 占16位
			String connectionId = System.currentTimeMillis()+StringUtil.getRandomString(3);
			boolean addSuccess = TcpChannelManager.add(port,connectionId, ctx);
			while(!addSuccess){
				connectionId = System.currentTimeMillis()+StringUtil.getRandomString(3);
				addSuccess = TcpChannelManager.add(port,connectionId, ctx);
			}
			attr.setIfAbsent(connectionId);
			
			//通知tunnel-client建立连接
			ChannelHandlerContext tunnelCtx = tunnelClient.getChannelHandlerContext();
			byte portIndexByte = (byte)(portIndex);
			TunnelDataQueueManager.commitData(TunnelDataQueueManager.TCP_CONNECT_MSG, tunnelCtx, new byte[]{portIndexByte},connectionId.getBytes());
			super.channelActive(ctx);
		}else{
			exceptionCaught(ctx,new Exception("no tunnelClient connected for port:"+port));
		}
    }
    
	@Override
	public void channelRead0(ChannelHandlerContext ctx, ByteBuf buf) throws Exception {
		byte[] data = new byte[buf.readableBytes()];
		buf.getBytes(buf.readerIndex(), data);
//		LogUtil.log("收到："+new String(data,1,data.length-1));
		TcpClient tunnelClient = TcpClientManager.get(port);
    	Attribute<String> attr = ctx.attr(TCP_CONNECTIONID_KEY);
		if(tunnelClient != null && attr.get() != null){
			ChannelHandlerContext tunnelCtx = tunnelClient.getChannelHandlerContext();
//				LogUtil.log("hi:"+hostIndexByte);
			byte[] connectionIdBytes = attr.get().getBytes();
//			LogUtil.log("发送给："+new String(connectionIdBytes));
        	TunnelDataQueueManager.commitData(TunnelDataQueueManager.TCP_DATA_MSG, tunnelCtx, connectionIdBytes,data);
		}else{
			byte[] response404 = HttpUtil.response404("tunnel-server");
			ctx.writeAndFlush(response404).addListener(ChannelFutureListener.CLOSE);
		}
	}
	
    @Override  
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
//        LogUtil.log("Tcp-Server exception");
    	super.exceptionCaught(ctx, cause);
        ctx.close();
    }

	@Override
    protected void handleWriterIdle(ChannelHandlerContext ctx) {
//        LogUtil.log("Tcp-Server timeout");
        super.handleReaderIdle(ctx);
        ctx.close();
    }
	
	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
//        LogUtil.log("Tcp-Server closing");
		super.channelInactive(ctx);
		Attribute<String> attr = ctx.attr(TCP_CONNECTIONID_KEY);
        if(attr.get() != null){
        	String connectionId = attr.get();
        	TcpChannelManager.remove(connectionId);
        }
//        LogUtil.log("Tcp-Server close success");
	}
	
}  